#include <windows.h>
#include <iostream>
#include <chrono>
#include <fstream>
#include <vector>
#include <iostream>
#include <fcntl.h>      // open
#include <thread>

void test() {
    const char* filename = "testfile.dat"; // 文件名用窄字符
    DWORD bytesPerSector = 0;

    // 查询当前驱动器扇区大小（使用窄字符版本 GetDiskFreeSpaceA）
    LPCSTR rootPath = "C:\\";
    DWORD sectorsPerCluster, freeClusters, totalClusters;
    if (!GetDiskFreeSpaceA(rootPath, &sectorsPerCluster, &bytesPerSector, &freeClusters, &totalClusters)) {
        std::cerr << "Failed to get disk sector size.\n";
        return;
    }
    std::cout << "Bytes per sector: " << bytesPerSector << "\n";

    // 打开文件
    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
        nullptr
    );

    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    // 分配对齐内存
    const size_t writeSize = 128 * 1024 * 1024; // 128MB
    void* buffer = _aligned_malloc(writeSize, bytesPerSector);
    if (!buffer) {
        std::cerr << "Failed to allocate aligned memory.\n";
        CloseHandle(hFile);
        return;
    }

    // 初始化全0
    memset(buffer, 0, writeSize);

    // 计算写入时间
    auto start = std::chrono::high_resolution_clock::now();

    DWORD bytesWritten = 0;
    if (!WriteFile(hFile, buffer, writeSize, &bytesWritten, nullptr)) {
        std::cerr << "WriteFile failed.\n";
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();

    std::cout << "Wrote " << bytesWritten / (1024 * 1024) << " MB in "
              << seconds << " seconds. Speed: "
              << (bytesWritten / (1024.0 * 1024.0)) / seconds
              << " MB/s\n";

    _aligned_free(buffer);
    CloseHandle(hFile);
}
void test_mmap() {
    const char* filename = "mmap_testfile.dat";
    const size_t writeSize = 128 * 1024 * 1024; // 128MB

    // 打开或创建文件
    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_READ | GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        nullptr
    );

    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    // 预分配文件大小
    LARGE_INTEGER filesize;
    filesize.QuadPart = writeSize;
    SetFilePointerEx(hFile, filesize, nullptr, FILE_BEGIN);
    SetEndOfFile(hFile);

    // 创建文件映射
    HANDLE hMap = CreateFileMappingA(hFile, nullptr, PAGE_READWRITE, 0, 0, nullptr);
    if (!hMap) {
        std::cerr << "Failed to create file mapping.\n";
        CloseHandle(hFile);
        return;
    }

    // 映射文件到内存
    char* ptr = (char*)MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, writeSize);
    if (!ptr) {
        std::cerr << "Failed to map view of file.\n";
        CloseHandle(hMap);
        CloseHandle(hFile);
        return;
    }

    // 初始化全0并测时间
    auto start = std::chrono::high_resolution_clock::now();
    memset(ptr, 0, writeSize);
    // 强制写回磁盘
    if (!FlushViewOfFile(ptr, writeSize)) {
        std::cerr << "FlushViewOfFile failed.\n";
    }
    auto end = std::chrono::high_resolution_clock::now();

    double seconds = std::chrono::duration<double>(end - start).count();
    std::cout << "MMap wrote " << writeSize / (1024 * 1024) << " MB in "
              << seconds << " seconds. Speed: "
              << (writeSize / (1024.0 * 1024.0)) / seconds
              << " MB/s\n";

    // 释放资源
    UnmapViewOfFile(ptr);
    CloseHandle(hMap);
    CloseHandle(hFile);
}
void test_filestream() {
    const char* filename = "fstream_testfile.dat";
    const size_t writeSize = 128 * 1024 * 1024; // 128MB

    // 分配缓冲区（可以用vector或new）
    std::vector<char> buffer(writeSize, 0); // 全0

    auto start = std::chrono::high_resolution_clock::now();

    std::ofstream ofs(filename, std::ios::binary | std::ios::trunc);
    if (!ofs.is_open()) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    // 写入整个缓冲区
    ofs.write(buffer.data(), buffer.size());
    ofs.close(); // flush

    auto end = std::chrono::high_resolution_clock::now();

    double seconds = std::chrono::duration<double>(end - start).count();
    std::cout << "ofstream wrote " << writeSize / (1024 * 1024) << " MB in "
              << seconds << " seconds. Speed: "
              << (writeSize / (1024.0 * 1024.0)) / seconds
              << " MB/s\n";
}
void write_5GB_file() {
    const char* filename = "testfile_5g.dat";
    DWORD bytesPerSector = 0;
    LPCSTR rootPath = "C:\\";
    DWORD sectorsPerCluster, freeClusters, totalClusters;
    if (!GetDiskFreeSpaceA(rootPath, &sectorsPerCluster, &bytesPerSector, &freeClusters, &totalClusters)) {
        std::cerr << "Failed to get disk sector size.\n";
        return;
    }
    std::cout << "Bytes per sector: " << bytesPerSector << "\n";

    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    const size_t totalSize = 5ULL * 1024 * 1024 * 1024; // 5GB
    const size_t chunkSize = 128 * 1024 * 1024;         // 128MB 分块写
    void* buffer = _aligned_malloc(chunkSize, bytesPerSector);
    if (!buffer) {
        std::cerr << "Failed to allocate aligned memory.\n";
        CloseHandle(hFile);
        return;
    }
    memset(buffer, 0, chunkSize);

    DWORD bytesWritten = 0;
    size_t written = 0;
    auto start = std::chrono::high_resolution_clock::now();

    while (written < totalSize) {
        size_t toWrite = (totalSize - written > chunkSize) ? chunkSize : (totalSize - written);
        DWORD bw = 0;
        if (!WriteFile(hFile, buffer, static_cast<DWORD>(toWrite), &bw, nullptr)) {
            std::cerr << "WriteFile failed.\n";
            break;
        }
        written += bw;
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();

    std::cout << "Wrote " << written / (1024.0 * 1024.0 * 1024.0) << " GB in "
              << seconds << " seconds. Speed: "
              << (written / (1024.0 * 1024.0 * 1024.0)) / seconds
              << " GB/s\n";

    _aligned_free(buffer);
    CloseHandle(hFile);
}
void test_mmap_5GB() {
    const char* filename = "mmap_5GB_testfile.dat";
    const size_t totalSize = 5ULL * 1024 * 1024 * 1024; // 5GB
    const size_t chunkSize = 128 * 1024 * 1024;          // 每次映射 128MB

    // 打开或创建文件
    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_READ | GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    // 预分配文件大小
    LARGE_INTEGER filesize;
    filesize.QuadPart = totalSize;
    SetFilePointerEx(hFile, filesize, nullptr, FILE_BEGIN);
    SetEndOfFile(hFile);

    // 写入全0并测时间
    auto start = std::chrono::high_resolution_clock::now();

    size_t written = 0;
    while (written < totalSize) {
        size_t thisChunk = (totalSize - written > chunkSize) ? chunkSize : (totalSize - written);

        HANDLE hMap = CreateFileMappingA(hFile, nullptr, PAGE_READWRITE, 0, 0, nullptr);
        if (!hMap) {
            std::cerr << "Failed to create file mapping.\n";
            break;
        }

        char* ptr = (char*)MapViewOfFile(hMap, FILE_MAP_WRITE, (DWORD)((written >> 32) & 0xFFFFFFFF), (DWORD)(written & 0xFFFFFFFF), thisChunk);
        if (!ptr) {
            std::cerr << "Failed to map view of file.\n";
            CloseHandle(hMap);
            break;
        }

        memset(ptr, 0, thisChunk);
        FlushViewOfFile(ptr, thisChunk);

        UnmapViewOfFile(ptr);
        CloseHandle(hMap);

        written += thisChunk;
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();

    std::cout << "MMap wrote " << written / (1024.0 * 1024.0 * 1024.0) << " GB in "
              << seconds << " seconds. Speed: "
              << (written / (1024.0 * 1024.0 * 1024.0)) / seconds
              << " GB/s\n";

    CloseHandle(hFile);
}
void write_25GB_increment_prepared() {
    const char* filename = "25GB_increment_prepared.dat";
    DWORD bytesPerSector = 0;
    DWORD sectorsPerCluster, freeClusters, totalClusters;
    if (!GetDiskFreeSpaceA("C:\\", &sectorsPerCluster, &bytesPerSector, &freeClusters, &totalClusters)) {
        std::cerr << "Failed to get disk sector size.\n";
        return;
    }

    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    const size_t totalSize = 5ULL * 1024 * 1024 * 1024 * 5; // 5GB
    const size_t chunkSize = 128 * 1024 * 1024;         // 128MB

    // 分配对齐内存
    uint32_t* buffer = (uint32_t*)_aligned_malloc(chunkSize, bytesPerSector);
    if (!buffer) {
        std::cerr << "Failed to allocate memory.\n";
        CloseHandle(hFile);
        return;
    }

    // 预先填充递增数据（循环覆盖整个块）
    size_t elements = chunkSize / sizeof(uint32_t);
    for (size_t i = 0; i < elements; ++i) buffer[i] = static_cast<uint32_t>(i);

    size_t written = 0;
    auto start = std::chrono::high_resolution_clock::now();

    while (written < totalSize) {
        size_t toWrite = (totalSize - written > chunkSize) ? chunkSize : (totalSize - written);

        DWORD bw = 0;
        if (!WriteFile(hFile, buffer, static_cast<DWORD>(toWrite), &bw, nullptr)) {
            std::cerr << "WriteFile failed.\n";
            break;
        }
        written += bw;
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();
    std::cout << "Wrote " << written / (1024.0 * 1024.0 * 1024.0) << " GB in "
              << seconds << " s. Speed: "
              << (written / (1024.0 * 1024.0 * 1024.0)) / seconds
              << " GB/s\n";

    _aligned_free(buffer);
    CloseHandle(hFile);
}
void mmap_5GB_increment_prepared() {
    const char* filename = "mmap_5GB_increment_prepared.dat";
    const size_t totalSize = 5ULL * 1024 * 1024 * 1024; // 5GB
    const size_t chunkSize = 128 * 1024 * 1024;          // 每次映射 128MB

    // 打开或创建文件
    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_READ | GENERIC_WRITE,
        0,
        nullptr,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file.\n";
        return;
    }

    // 预分配文件大小
    LARGE_INTEGER filesize;
    filesize.QuadPart = totalSize;
    SetFilePointerEx(hFile, filesize, nullptr, FILE_BEGIN);
    SetEndOfFile(hFile);

    // 提前准备递增数内存块
    uint32_t* memBlock = new uint32_t[chunkSize / sizeof(uint32_t)];
    size_t elements = chunkSize / sizeof(uint32_t);
    for (size_t i = 0; i < elements; ++i) memBlock[i] = static_cast<uint32_t>(i);

    size_t written = 0;
    uint32_t offset = 0; // 跨块递增偏移
    auto start = std::chrono::high_resolution_clock::now();

    while (written < totalSize) {
        size_t thisChunk = (totalSize - written > chunkSize) ? chunkSize : (totalSize - written);

        // 创建文件映射
        HANDLE hMap = CreateFileMappingA(hFile, nullptr, PAGE_READWRITE, 0, 0, nullptr);
        if (!hMap) {
            std::cerr << "Failed to create file mapping.\n";
            break;
        }

        char* ptr = (char*)MapViewOfFile(hMap, FILE_MAP_WRITE,
                                         (DWORD)((written >> 32) & 0xFFFFFFFF),
                                         (DWORD)(written & 0xFFFFFFFF),
                                         thisChunk);
        if (!ptr) {
            std::cerr << "Failed to map view of file.\n";
            CloseHandle(hMap);
            break;
        }

        // 拷贝内存块到映射
        size_t copyElements = thisChunk / sizeof(uint32_t);
        for (size_t i = 0; i < copyElements; ++i) {
            reinterpret_cast<uint32_t*>(ptr)[i] = memBlock[(i + offset) % elements];
        }
        offset = (offset + copyElements) % elements;

        FlushViewOfFile(ptr, thisChunk);
        UnmapViewOfFile(ptr);
        CloseHandle(hMap);

        written += thisChunk;
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();
    std::cout << "MMap wrote " << written / (1024.0 * 1024.0 * 1024.0) << " GB in "
              << seconds << " s. Speed: "
              << (written / (1024.0 * 1024.0 * 1024.0)) / seconds
              << " GB/s\n";

    delete[] memBlock;
    CloseHandle(hFile);
}
void write_25GB_increment_prepared_a() {
    const char* filename = "25GB_increment_prepared.dat";
    DWORD bytesPerSector = 0, sectorsPerCluster, freeClusters, totalClusters;
    if (!GetDiskFreeSpaceA("C:\\", &sectorsPerCluster, &bytesPerSector, &freeClusters, &totalClusters)) {
        std::cerr << "Failed to get disk sector size. Error: " << GetLastError() << "\n";
        return;
    }

    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_WRITE,
        FILE_SHARE_READ,
        nullptr,
        CREATE_ALWAYS,
        FILE_FLAG_NO_BUFFERING  | FILE_FLAG_SEQUENTIAL_SCAN,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file. Error: " << GetLastError() << "\n";
        return;
    }

    const size_t totalSize = 25ULL * 1024 * 1024 * 1024; // 25GB
    const size_t chunkSize = 128ULL * 1024 * 1024;       // 128MB
    if (totalSize % bytesPerSector != 0 || chunkSize % bytesPerSector != 0) {
        std::cerr << "Size not aligned to sector size!\n";
        CloseHandle(hFile);
        return;
    }

    uint32_t* buffer = (uint32_t*)_aligned_malloc(chunkSize, bytesPerSector);
    if (!buffer) {
        std::cerr << "Failed to allocate memory.\n";
        CloseHandle(hFile);
        return;
    }

    size_t elements = chunkSize / sizeof(uint32_t);
    for (size_t i = 0; i < elements; ++i)
        buffer[i] = static_cast<uint32_t>(i);

    size_t written = 0;
    auto start = std::chrono::high_resolution_clock::now();

    while (written < totalSize) {
        DWORD bw = 0;
        if (!WriteFile(hFile, buffer, (DWORD)chunkSize, &bw, nullptr)) {
            std::cerr << "WriteFile failed. Error: " << GetLastError() << "\n";
            break;
        }
        written += bw;
    }
    FlushFileBuffers(hFile);
    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();
    std::cout << "Wrote " << written / (1024.0 * 1024.0 * 1024.0)
              << " GB in " << seconds << " s. Speed: "
              << (written / (1024.0 * 1024.0 * 1024.0)) / seconds
              << " GB/s\n";

    _aligned_free(buffer);
    CloseHandle(hFile);
}
void verify_25GB_increment_prepared() {
    const char* filename = "25GB_increment_prepared.dat";
    DWORD bytesPerSector = 0, sectorsPerCluster, freeClusters, totalClusters;
    if (!GetDiskFreeSpaceA("C:\\", &sectorsPerCluster, &bytesPerSector, &freeClusters, &totalClusters)) {
        std::cerr << "Failed to get disk sector size. Error: " << GetLastError() << "\n";
        return;
    }

    HANDLE hFile = CreateFileA(
        filename,
        GENERIC_READ,
        FILE_SHARE_READ,
        nullptr,
        OPEN_EXISTING,
        FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN,
        nullptr
    );
    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "Failed to open file for read. Error: " << GetLastError() << "\n";
        return;
    }

    const size_t totalSize = 25ULL * 1024 * 1024 * 1024; // 25GB
    const size_t chunkSize = 128ULL * 1024 * 1024;       // 128MB
    if (totalSize % bytesPerSector != 0 || chunkSize % bytesPerSector != 0) {
        std::cerr << "Size not aligned to sector size!\n";
        CloseHandle(hFile);
        return;
    }

    uint32_t* buffer = (uint32_t*)_aligned_malloc(chunkSize, bytesPerSector);
    if (!buffer) {
        std::cerr << "Failed to allocate read buffer.\n";
        CloseHandle(hFile);
        return;
    }

    size_t readTotal = 0;
    bool verifyFailed = false;
    uint64_t expected = 0;

    auto start = std::chrono::high_resolution_clock::now();

    while (readTotal < totalSize) {
        DWORD br = 0;
        if (!ReadFile(hFile, buffer, (DWORD)chunkSize, &br, nullptr)) {
            std::cerr << "ReadFile failed. Error: " << GetLastError() << "\n";
            verifyFailed = true;
            break;
        }
        if (br == 0)
            break;

        size_t count = br / sizeof(uint32_t);
        for (size_t i = 0; i < count; ++i) {
            uint32_t val = buffer[i];
            uint32_t ref = static_cast<uint32_t>(i);
            if (val != ref) {
                std::cerr << "Data mismatch at block " << (readTotal / chunkSize)
                          << ", index " << i
                          << ". Got " << val << ", expected " << ref << "\n";
                verifyFailed = true;
                break;
            }
        }

        if (verifyFailed)
            break;

        readTotal += br;
    }

    auto end = std::chrono::high_resolution_clock::now();
    double seconds = std::chrono::duration<double>(end - start).count();

    if (!verifyFailed) {
        std::cout << "Verified " << readTotal / (1024.0 * 1024.0 * 1024.0)
                  << " GB in " << seconds << " s. Read speed: "
                  << (readTotal / (1024.0 * 1024.0 * 1024.0)) / seconds
                  << " GB/s\n✅ Verification PASSED\n";
    } else {
        std::cerr << "❌ Verification FAILED after " << readTotal / (1024.0 * 1024.0 * 1024.0)
                  << " GB.\n";
    }

    _aligned_free(buffer);
    CloseHandle(hFile);
}
int main() {
    // mmap_5GB_increment_prepared();
    // write_25GB_increment_prepared_a();
    verify_25GB_increment_prepared();
    return 0;
}
